#include "LireXML.h"
#include <iostream>

#include <QtCore/QFile>
#include <QtCore/QString>

#include "Qlib.h"

using namespace std;

DebugLevelType LireXML::interne( BLANK );

/**
 * Constructeur par défaut. Lit l'arbre DOM par récursion et remplit
 * la map Information.
 *
 * @param[in] nom fichier à ouvrir
 */
LireXML::LireXML( const string& nom )
  : QObject(), ADDObjetBase( "LireXML" ), ajouterPlus( false ), ajout( "" )
{
  QFile file(nom.c_str());
  if (!file.open(QIODevice::ReadOnly))
    return;
  if (!doc.setContent(&file))
    {
      /* établit le document XML à partir des données du fichier
	 (hiérarchie, etc) */
      file.close(); 
      return;
    }
  file.close();

  lire();
}

/**
 * Destructeur, ne fait rien de spécial.
 */
LireXML::~LireXML()
{}

/**
 * Effectue la lecture de l'arbre DOM. Pour chaque noeud trouvé, on
 * cherche ses enfants.
 *
 * Le niveau de sortie est paramétré par LireXML::interne :\n
 * - \e FUNC affiche les messages de début et de fin de méthode.\n
 * - \e LINFO affiche le nom de chaque noeud trouvé.
 */
void LireXML::lire()
{
  /*Debug::*/empileNiveau( &LireXML::interne );
  func() << "LireXML::lire -> début" << endmsg;

  QString affichage;
  QDomNodeList tab;
  QDomElement element;
  QDomNode n;
  QDomElement racine( doc.documentElement() ); //renvoie la balise racine
  QDomNode noeud( racine.firstChild() ); //renvoie la 1ère balise

  while (noeud.nodeType() != QDomNode::ElementNode)
    {
      noeud = noeud.nextSibling();
    }

  do
    {
      trouverEnfants(noeud);
      noeud = noeud.nextSibling();
      linfo() << "Noeud suivant : "
	      << noeud.toElement().tagName().toStdString() << endmsg;
    }
  while (!noeud.isNull());

  func() << "LireXML::lire -> fin" << endmsg;
  /*Debug::*/depileNiveau();
}

/**
 * Permet de récupérer les informations lues.
 *
 * @param[out] info std::map contenant les information xml, le format
 * est <tag, valeur>.
 */
void LireXML::getInformation(map<string, string>& info) const
{
  map<std::string, std::string>::const_iterator it, Begin(Information.begin()),
    End(Information.end());

  info.clear();

  for (it = Begin; it != End; it++)
    info[it -> first] = it -> second;
}

/**
 * Permet de vérifier si la lecture s'est bien déroulée. On véréfie
 * ici que le conteneur associatif n'est pas vide.
 *
 * @return \e false si le conteneur est vide (càd aucune information
 * n'a pu être lue), \e true sinon.
 */
bool LireXML::estOK() const
{
  if ( Information.begin() == Information.end() )
    return false;
  else
    return true;
}

/**
 * Permet de modifier la valeur de LireXML::interne.
 *
 * @param[in] level nouvelle valeur de LireXML::interne.
 */
void LireXML::setLevel( const DebugLevelType& level, const unsigned& )
{
  interne = level;
}

/**
 * Méthode récursive de récupération des informations contenues dans
 * l'arbre DOM. A chaque appel on regarde si le noeud a des enfants,
 * si oui on cherche leurs enfants. S'il n'existe pas d'enfant, alors
 * il s'agit d'un champ de donnée que l'on lit.
 *
 * Le fonctionnement exact est en fait juste l'inverse : on détecte si
 * le noeud est un champ de données, et sinon on cherche ses enfants.
 *
 * Le niveau est paramétré par LireXML::interne :\n
 * - \e FUNC affiche les messages de début et de fin de méthode.\n
 * - \e LFUNC affiche le nom du noeud dont on cherche les enfants.\n
 * - \e DEBUG affiche la paire balise - données pour chaque champ de
 * donnée lu.
 *
 * @param[in,out] noeud élément de l'arborescence DOM pour lequel on
 * cherche ses enfants / la valeur qui lui est associée.
 */
void LireXML::trouverEnfants(QDomNode& noeud)
{
  func() << "LireXML::trouverEnfants -> début" << endmsg;

  lfunc() << "On cherche les enfants de "
	  << noeud.toElement().tagName().toStdString() << endmsg;

  unsigned int i, size;
  QString affichage;
  QDomElement element;
  QDomNodeList tab;
  QDomNode n;
  QString qtag, qval;
  string tag, val;
  
  element = noeud.toElement();
  tab = element.childNodes();
  size = tab.length();

  ajouterPlus = ( noeud.parentNode().toElement().tagName().toStdString()
		  == "Info_Classe" );

  for(i = 0; i < size; i++)
    {
      n = tab.item(i);

      if ( n.nodeType() == QDomNode::TextNode )
	{
	  qtag = element.tagName();
	  tag = qtag.toStdString();
	  // Trim => on enlève les espaces avant et après :-)
	  qval =  n.toText().data().trimmed();
	  val = toUtf8StdString( qval );

	  if ( tag == "Classe" )
	    {
	      while (Information.find(tag + ajout) != Information.end())
		ajout += '+';
	    }

	  if ( ajouterPlus )
	    {
	      tag += ajout;
	    }
	  Information[tag] = val;
	  debug() << "Trouvé valeurs : "
		  << toUtf8StdString( n.toText().data() ) << " pour "
		  << toUtf8StdString( qtag ) << endmsg;
	  
	  func() << "LireXML::trouverEnfants -> fin" << endmsg;
	}
      else
	{
	  func() << "LireXML::trouverEnfants -> fin" << endmsg;
	  trouverEnfants(n);
	}
    }
}
